package com.bestcem.xm.survey.service.impl;

import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateTime;
import cn.hutool.jwt.JWT;
import cn.hutool.jwt.JWTPayload;
import cn.hutool.jwt.JWTUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.survey.service.JwtTokenService;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

import static com.bestcem.xm.survey.util.SurveyConstant.USER_TOKEN_VERSION_FORMAT_KEY;

@Service
@RequiredArgsConstructor
@Slf4j
public class JwtTokenServiceImpl implements JwtTokenService {

    @Value("${jwt.secret-key:9C4E23F8-128D-475F-1111-587AFC8B18BC}")
    private String secret;
    @Value("${jwt.timeout:7200}")
    private Integer timeout;
    @Value("${jwt.refresh-timeout:43200}")
    private Integer refreshTimeout;
    @Value("${jwt.issuer:'IDY:MX'}")
    private String issuer;
    @Value("${jwt.not-before:true}")
    private Boolean notBefore;

    private @NonNull RedisService redisService;

    @Override
    public String createToken(Map<String, Object> headers, Map<String, Object> kwargs, Integer time_out) {
        if (time_out == null || time_out <= 0) {
            time_out = timeout;
        }
        DateTime now = DateTime.now();
        DateTime expTime = now.offsetNew(DateField.SECOND, time_out);

        Map<String, Object> payload = new HashMap<>();
        //过期时间exp
        payload.put(JWTPayload.EXPIRES_AT, expTime);
        //签发时间iat
        payload.put(JWTPayload.ISSUED_AT, now);
        //签发者iss
        payload.put(JWTPayload.ISSUER, issuer);

        if (Objects.nonNull(kwargs.get("uid"))) {
            String user_id = kwargs.get("uid").toString();
            String prefix = String.format(USER_TOKEN_VERSION_FORMAT_KEY, user_id);
            Object ver = redisService.get(prefix);
            if (Objects.nonNull(ver)) {
                payload.put("token_ver", Integer.parseInt(ver.toString()));
            }
        }

        //生效时间nbf
        if (Boolean.TRUE.equals(notBefore)) {
            payload.put(JWTPayload.NOT_BEFORE, now);
        }
        //动态载荷
        payload.putAll(kwargs);

        return JWTUtil.createToken(headers, payload, secret.getBytes());
    }

    @Override
    public boolean validateToken(String token, Long leeway) {
        boolean pass = JWTUtil.verify(token, secret.getBytes());
        if (pass && Objects.nonNull(leeway)) {
            JWT jwt = JWTUtil.parseToken(token);
            jwt.setKey(secret.getBytes());
            return jwt.validate(leeway);
        }
        return pass;
    }

    @Override
    public Map<String, Object> getPayloads(String token) {
        boolean pass = JWTUtil.verify(token, secret.getBytes());
        if (pass) {
            JWT jwt = JWTUtil.parseToken(token);
            jwt.setKey(secret.getBytes());
            return jwt.getPayloads();
        }
        return null;
    }

    @Override
    public Map<String, Object> getHeaders(String token) {
        boolean pass = JWTUtil.verify(token, secret.getBytes());
        if (pass) {
            JWT jwt = JWTUtil.parseToken(token);
            jwt.setKey(secret.getBytes());
            return jwt.getHeaders();
        }
        return null;
    }

}




